/* Copyright (c) 2011-2022 Reliancy LLC Licensed under the GNU LESSER GENERAL PUBLIC LICENSE Version 3. You may obtain a copy of the License at https://www.gnu.org/licenses/lgpl-3.0.en.html. You may not use this file except in compliance with the License. */ package com.reliancy.dbo; import java.util.HashMap; import java.util.Iterator; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.util.ArrayList; import java.util.Collection; import com.reliancy.rec.Hdr; import com.reliancy.rec.Slot; /** Describes an object structure, usually a table. * */ public class Entity extends Hdr{ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public static @interface Info { String name(); } static final HashMap registry=new HashMap<>(); public static final void publish(Entity ent){ registry.put(ent.getName(),ent); registry.put(ent.getId(),ent); } public static final void retract(Entity ent){ if(ent==null) return; Collection vals=registry.values(); while(vals.remove(ent)){} } public static final void retract(Class cls){ Entity ent=recall(cls.getSimpleName()); if(ent!=null){ retract(ent); } } public static final Entity recall(String name){ return registry.get(name); } public static final Entity recall(Class cls){ Entity ent=recall(cls.getSimpleName()); if(ent==null){ ent=publish(cls); } return ent; } /** * this method will analyze a DBO class and forumate an Entity object out of it. * @param cls * @return */ @SuppressWarnings("unchecked") public static final Entity publish(Class cls){ Entity ret=registry.get(cls.getSimpleName()); if(ret!=null) return ret; //System.out.println("Analyzing:"+cls); Class base=cls.getSuperclass(); Entity base_ent=null; int position0=0; if(base!=null && base!=DBO.class){ base_ent=publish((Class)base); position0=base_ent.count(); } java.lang.reflect.Field[] declaredFields = cls.getDeclaredFields(); ArrayList slots=new ArrayList<>(); for (java.lang.reflect.Field field : declaredFields) { if (!java.lang.reflect.Modifier.isStatic(field.getModifiers())) { continue; } try { String sf_name=field.getName(); Field slot=(Field) field.get(cls); // Only set ID if not already set (allows explicit database column name mapping) // Use Field's name (database column name) if available, otherwise use Java field name if(slot.getId()==null || slot.getId().isEmpty()){ String dbName=slot.getName(); // This is the name passed to Field constructor (e.g., "created_on") if(dbName!=null && !dbName.isEmpty()){ slot.setId(dbName); }else{ slot.setId(sf_name); // Fallback to Java field name } } slot.setPosition(position0+slots.size()); slots.add(slot); //System.out.println(sf_name+":"+slot+" atpos:"+slot.getPosition()); } catch (Exception e) { } } Info info=cls.getAnnotation(Info.class); ret=new Entity(info!=null?info.name():cls.getSimpleName()).setId(cls.getSimpleName()); ret.setBase(base_ent); ret.setType(cls); ret.getOwnSlots().addAll(slots); publish(ret); return ret; } Entity base; String id; Field pk; public Entity(String name) { super(name); } @Override public Slot makeSlot(String name){ return new Field(name); } @Override public Iterator iterator(int offset){ if(offset>0) throw new IllegalArgumentException("Offset not supported"); final Entity ent=this; return new Iterator(){ final FieldSlice slice=new FieldSlice(ent).including(Field.FLAG_STORABLE); @Override public boolean hasNext() { return slice.hasNext(); } @Override public Slot next() { return slice.next(); } }; } @Override public int count(){ return super.count()+(base!=null?base.count():0); } /** * gets a slot which could be here or in base. */ @Override public Slot getSlot(int pos){ if(base!=null){ // we got base int ofs=base.count(); if(pos cls=getType(); DBO ret=(DBO) cls.newInstance(); ret.setType(this).setTerminal(t).setStatus(DBO.Status.NEW); return ret; } }