annotationSpecs) {
135 | checkArgument(annotationSpecs != null, "annotationSpecs == null");
136 | for (AnnotationSpec annotationSpec : annotationSpecs) {
137 | this.annotations.add(annotationSpec);
138 | }
139 | return this;
140 | }
141 |
142 | public Builder addAnnotation(AnnotationSpec annotationSpec) {
143 | this.annotations.add(annotationSpec);
144 | return this;
145 | }
146 |
147 | public Builder addAnnotation(ClassName annotation) {
148 | this.annotations.add(AnnotationSpec.builder(annotation).build());
149 | return this;
150 | }
151 |
152 | public Builder addAnnotation(Class> annotation) {
153 | return addAnnotation(ClassName.get(annotation));
154 | }
155 |
156 | public Builder addModifiers(Modifier... modifiers) {
157 | Collections.addAll(this.modifiers, modifiers);
158 | return this;
159 | }
160 |
161 | public Builder initializer(String format, Object... args) {
162 | return initializer(CodeBlock.of(format, args));
163 | }
164 |
165 | public Builder initializer(CodeBlock codeBlock) {
166 | checkState(this.initializer == null, "initializer was already set");
167 | this.initializer = checkNotNull(codeBlock, "codeBlock == null");
168 | return this;
169 | }
170 |
171 | public FieldSpec build() {
172 | return new FieldSpec(this);
173 | }
174 | }
175 | }
176 |
--------------------------------------------------------------------------------
/x2c-apt/src/main/java/com/squareup/javapoet/x2c/LineWrapper.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 Square, Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.squareup.javapoet.x2c;
17 |
18 | import java.io.IOException;
19 |
20 | import static com.squareup.javapoet.x2c.Util.checkNotNull;
21 |
22 | /**
23 | * Implements soft line wrapping on an appendable. To use, append characters using {@link #append}
24 | * or soft-wrapping spaces using {@link #wrappingSpace}.
25 | */
26 | final class LineWrapper {
27 | private final Appendable out;
28 | private final String indent;
29 | private final int columnLimit;
30 | private boolean closed;
31 |
32 | /** Characters written since the last wrapping space that haven't yet been flushed. */
33 | private final StringBuilder buffer = new StringBuilder();
34 |
35 | /** The number of characters since the most recent newline. Includes both out and the buffer. */
36 | private int column = 0;
37 |
38 | /**
39 | * -1 if we have no buffering; otherwise the number of {@code indent}s to write after wrapping.
40 | */
41 | private int indentLevel = -1;
42 |
43 | /**
44 | * Null if we have no buffering; otherwise the type to pass to the next call to {@link #flush}.
45 | */
46 | private FlushType nextFlush;
47 |
48 | LineWrapper(Appendable out, String indent, int columnLimit) {
49 | checkNotNull(out, "out == null");
50 | this.out = out;
51 | this.indent = indent;
52 | this.columnLimit = columnLimit;
53 | }
54 |
55 | /** Emit {@code s}. This may be buffered to permit line wraps to be inserted. */
56 | void append(String s) throws IOException {
57 | if (closed) throw new IllegalStateException("closed");
58 |
59 | if (nextFlush != null) {
60 | int nextNewline = s.indexOf('\n');
61 |
62 | // If s doesn't cause the current line to cross the limit, buffer it and return. We'll decide
63 | // whether or not we have to wrap it later.
64 | if (nextNewline == -1 && column + s.length() <= columnLimit) {
65 | buffer.append(s);
66 | column += s.length();
67 | return;
68 | }
69 |
70 | // Wrap if appending s would overflow the current line.
71 | boolean wrap = nextNewline == -1 || column + nextNewline > columnLimit;
72 | flush(wrap ? FlushType.WRAP : nextFlush);
73 | }
74 |
75 | out.append(s);
76 | int lastNewline = s.lastIndexOf('\n');
77 | column = lastNewline != -1
78 | ? s.length() - lastNewline - 1
79 | : column + s.length();
80 | }
81 |
82 | /** Emit either a space or a newline character. */
83 | void wrappingSpace(int indentLevel) throws IOException {
84 | if (closed) throw new IllegalStateException("closed");
85 |
86 | if (this.nextFlush != null) flush(nextFlush);
87 | column++; // Increment the column even though the space is deferred to next call to flush().
88 | this.nextFlush = FlushType.SPACE;
89 | this.indentLevel = indentLevel;
90 | }
91 |
92 | /** Emit a newline character if the line will exceed it's limit, otherwise do nothing. */
93 | void zeroWidthSpace(int indentLevel) throws IOException {
94 | if (closed) throw new IllegalStateException("closed");
95 |
96 | if (column == 0) return;
97 | if (this.nextFlush != null) flush(nextFlush);
98 | this.nextFlush = FlushType.EMPTY;
99 | this.indentLevel = indentLevel;
100 | }
101 |
102 | /** Flush any outstanding text and forbid future writes to this line wrapper. */
103 | void close() throws IOException {
104 | if (nextFlush != null) flush(nextFlush);
105 | closed = true;
106 | }
107 |
108 | /** Write the space followed by any buffered text that follows it. */
109 | private void flush(FlushType flushType) throws IOException {
110 | switch (flushType) {
111 | case WRAP:
112 | out.append('\n');
113 | for (int i = 0; i < indentLevel; i++) {
114 | out.append(indent);
115 | }
116 | column = indentLevel * indent.length();
117 | column += buffer.length();
118 | break;
119 | case SPACE:
120 | out.append(' ');
121 | break;
122 | case EMPTY:
123 | break;
124 | default:
125 | throw new IllegalArgumentException("Unknown FlushType: " + flushType);
126 | }
127 |
128 | out.append(buffer);
129 | buffer.delete(0, buffer.length());
130 | indentLevel = -1;
131 | nextFlush = null;
132 | }
133 |
134 | private enum FlushType {
135 | WRAP, SPACE, EMPTY;
136 | }
137 | }
138 |
--------------------------------------------------------------------------------
/x2c-apt/src/main/java/com/squareup/javapoet/x2c/NameAllocator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 Square, Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.squareup.javapoet.x2c;
17 |
18 | import java.util.LinkedHashMap;
19 | import java.util.LinkedHashSet;
20 | import java.util.Map;
21 | import java.util.Set;
22 | import java.util.UUID;
23 |
24 | import javax.lang.model.SourceVersion;
25 |
26 | import static com.squareup.javapoet.x2c.Util.checkNotNull;
27 |
28 | /**
29 | * Assigns Java identifier names to avoid collisions, keywords, and invalid characters. To use,
30 | * first create an instance and allocate all of the names that you need. Typically this is a
31 | * mix of user-supplied names and constants: {@code
32 | *
33 | * NameAllocator nameAllocator = new NameAllocator();
34 | * for (MyProperty property : properties) {
35 | * nameAllocator.newName(property.name(), property);
36 | * }
37 | * nameAllocator.newName("sb", "string builder");
38 | * }
39 | *
40 | * Pass a unique tag object to each allocation. The tag scopes the name, and can be used to look up
41 | * the allocated name later. Typically the tag is the object that is being named. In the above
42 | * example we use {@code property} for the user-supplied property names, and {@code "string
43 | * builder"} for our constant string builder.
44 | *
45 | * Once we've allocated names we can use them when generating code:
{@code
46 | *
47 | * MethodSpec.Builder builder = MethodSpec.methodBuilder("toString")
48 | * .addAnnotation(Override.class)
49 | * .addModifiers(Modifier.PUBLIC)
50 | * .returns(String.class);
51 | *
52 | * builder.addStatement("$1T $2N = new $1T()",
53 | * StringBuilder.class, nameAllocator.get("string builder"));
54 | * for (MyProperty property : properties) {
55 | * builder.addStatement("$N.append($N)",
56 | * nameAllocator.get("string builder"), nameAllocator.get(property));
57 | * }
58 | * builder.addStatement("return $N", nameAllocator.get("string builder"));
59 | * return builder.build();
60 | * }
61 | *
62 | * The above code generates unique names if presented with conflicts. Given user-supplied properties
63 | * with names {@code ab} and {@code sb} this generates the following: {@code
64 | *
65 | * @Override
66 | * public String toString() {
67 | * StringBuilder sb_ = new StringBuilder();
68 | * sb_.append(ab);
69 | * sb_.append(sb);
70 | * return sb_.toString();
71 | * }
72 | * }
73 | *
74 | * The underscore is appended to {@code sb} to avoid conflicting with the user-supplied {@code sb}
75 | * property. Underscores are also prefixed for names that start with a digit, and used to replace
76 | * name-unsafe characters like space or dash.
77 | *
78 | * When dealing with multiple independent inner scopes, use a {@link #clone()} of the
79 | * NameAllocator used for the outer scope to further refine name allocation for a specific inner
80 | * scope.
81 | */
82 | public final class NameAllocator implements Cloneable {
83 | private final Set allocatedNames;
84 | private final Map tagToName;
85 |
86 | public NameAllocator() {
87 | this(new LinkedHashSet<>(), new LinkedHashMap<>());
88 | }
89 |
90 | private NameAllocator(LinkedHashSet allocatedNames,
91 | LinkedHashMap tagToName) {
92 | this.allocatedNames = allocatedNames;
93 | this.tagToName = tagToName;
94 | }
95 |
96 | /**
97 | * Return a new name using {@code suggestion} that will not be a Java identifier or clash with
98 | * other names.
99 | */
100 | public String newName(String suggestion) {
101 | return newName(suggestion, UUID.randomUUID().toString());
102 | }
103 |
104 | /**
105 | * Return a new name using {@code suggestion} that will not be a Java identifier or clash with
106 | * other names. The returned value can be queried multiple times by passing {@code tag} to
107 | * {@link #get(Object)}.
108 | */
109 | public String newName(String suggestion, Object tag) {
110 | checkNotNull(suggestion, "suggestion");
111 | checkNotNull(tag, "tag");
112 |
113 | suggestion = toJavaIdentifier(suggestion);
114 |
115 | while (SourceVersion.isKeyword(suggestion) || !allocatedNames.add(suggestion)) {
116 | suggestion = suggestion + "_";
117 | }
118 |
119 | String replaced = tagToName.put(tag, suggestion);
120 | if (replaced != null) {
121 | tagToName.put(tag, replaced); // Put things back as they were!
122 | throw new IllegalArgumentException("tag " + tag + " cannot be used for both '" + replaced
123 | + "' and '" + suggestion + "'");
124 | }
125 |
126 | return suggestion;
127 | }
128 |
129 | public static String toJavaIdentifier(String suggestion) {
130 | StringBuilder result = new StringBuilder();
131 | for (int i = 0; i < suggestion.length(); ) {
132 | int codePoint = suggestion.codePointAt(i);
133 | if (i == 0
134 | && !Character.isJavaIdentifierStart(codePoint)
135 | && Character.isJavaIdentifierPart(codePoint)) {
136 | result.append("_");
137 | }
138 |
139 | int validCodePoint = Character.isJavaIdentifierPart(codePoint) ? codePoint : '_';
140 | result.appendCodePoint(validCodePoint);
141 | i += Character.charCount(codePoint);
142 | }
143 | return result.toString();
144 | }
145 |
146 | /** Retrieve a name created with {@link #newName(String, Object)}. */
147 | public String get(Object tag) {
148 | String result = tagToName.get(tag);
149 | if (result == null) {
150 | throw new IllegalArgumentException("unknown tag: " + tag);
151 | }
152 | return result;
153 | }
154 |
155 | /**
156 | * Create a deep copy of this NameAllocator. Useful to create multiple independent refinements
157 | * of a NameAllocator to be used in the respective definition of multiples, independently-scoped,
158 | * inner code blocks.
159 | *
160 | * @return A deep copy of this NameAllocator.
161 | */
162 | @Override
163 | public NameAllocator clone() {
164 | return new NameAllocator(
165 | new LinkedHashSet<>(this.allocatedNames),
166 | new LinkedHashMap<>(this.tagToName));
167 | }
168 |
169 | }
170 |
--------------------------------------------------------------------------------
/x2c-apt/src/main/java/com/squareup/javapoet/x2c/ParameterSpec.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 Square, Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.squareup.javapoet.x2c;
17 |
18 | import java.io.IOException;
19 | import java.lang.reflect.Type;
20 | import java.util.ArrayList;
21 | import java.util.Collections;
22 | import java.util.List;
23 | import java.util.Set;
24 |
25 | import javax.lang.model.SourceVersion;
26 | import javax.lang.model.element.ExecutableElement;
27 | import javax.lang.model.element.Modifier;
28 | import javax.lang.model.element.VariableElement;
29 |
30 | import static com.squareup.javapoet.x2c.Util.checkArgument;
31 | import static com.squareup.javapoet.x2c.Util.checkNotNull;
32 |
33 | /** A generated parameter declaration. */
34 | public final class ParameterSpec {
35 | public final String name;
36 | public final List annotations;
37 | public final Set modifiers;
38 | public final TypeName type;
39 |
40 | private ParameterSpec(Builder builder) {
41 | this.name = checkNotNull(builder.name, "name == null");
42 | this.annotations = Util.immutableList(builder.annotations);
43 | this.modifiers = Util.immutableSet(builder.modifiers);
44 | this.type = checkNotNull(builder.type, "type == null");
45 | }
46 |
47 | public boolean hasModifier(Modifier modifier) {
48 | return modifiers.contains(modifier);
49 | }
50 |
51 | void emit(CodeWriter codeWriter, boolean varargs) throws IOException {
52 | codeWriter.emitAnnotations(annotations, true);
53 | codeWriter.emitModifiers(modifiers);
54 | if (varargs) {
55 | TypeName.asArray(type).emit(codeWriter, true);
56 | } else {
57 | type.emit(codeWriter);
58 | }
59 | codeWriter.emit(" $L", name);
60 | }
61 |
62 | @Override public boolean equals(Object o) {
63 | if (this == o) return true;
64 | if (o == null) return false;
65 | if (getClass() != o.getClass()) return false;
66 | return toString().equals(o.toString());
67 | }
68 |
69 | @Override public int hashCode() {
70 | return toString().hashCode();
71 | }
72 |
73 | @Override public String toString() {
74 | StringBuilder out = new StringBuilder();
75 | try {
76 | CodeWriter codeWriter = new CodeWriter(out);
77 | emit(codeWriter, false);
78 | return out.toString();
79 | } catch (IOException e) {
80 | throw new AssertionError();
81 | }
82 | }
83 |
84 | public static ParameterSpec get(VariableElement element) {
85 | TypeName type = TypeName.get(element.asType());
86 | String name = element.getSimpleName().toString();
87 | return ParameterSpec.builder(type, name)
88 | .addModifiers(element.getModifiers())
89 | .build();
90 | }
91 |
92 | static List parametersOf(ExecutableElement method) {
93 | List result = new ArrayList<>();
94 | for (VariableElement parameter : method.getParameters()) {
95 | result.add(ParameterSpec.get(parameter));
96 | }
97 | return result;
98 | }
99 |
100 | public static Builder builder(TypeName type, String name, Modifier... modifiers) {
101 | checkNotNull(type, "type == null");
102 | checkArgument(SourceVersion.isName(name), "not a valid name: %s", name);
103 | return new Builder(type, name)
104 | .addModifiers(modifiers);
105 | }
106 |
107 | public static Builder builder(Type type, String name, Modifier... modifiers) {
108 | return builder(TypeName.get(type), name, modifiers);
109 | }
110 |
111 | public Builder toBuilder() {
112 | return toBuilder(type, name);
113 | }
114 |
115 | Builder toBuilder(TypeName type, String name) {
116 | Builder builder = new Builder(type, name);
117 | builder.annotations.addAll(annotations);
118 | builder.modifiers.addAll(modifiers);
119 | return builder;
120 | }
121 |
122 | public static final class Builder {
123 | private final TypeName type;
124 | private final String name;
125 |
126 | private final List annotations = new ArrayList<>();
127 | private final List modifiers = new ArrayList<>();
128 |
129 | private Builder(TypeName type, String name) {
130 | this.type = type;
131 | this.name = name;
132 | }
133 |
134 | public Builder addAnnotations(Iterable annotationSpecs) {
135 | checkArgument(annotationSpecs != null, "annotationSpecs == null");
136 | for (AnnotationSpec annotationSpec : annotationSpecs) {
137 | this.annotations.add(annotationSpec);
138 | }
139 | return this;
140 | }
141 |
142 | public Builder addAnnotation(AnnotationSpec annotationSpec) {
143 | this.annotations.add(annotationSpec);
144 | return this;
145 | }
146 |
147 | public Builder addAnnotation(ClassName annotation) {
148 | this.annotations.add(AnnotationSpec.builder(annotation).build());
149 | return this;
150 | }
151 |
152 | public Builder addAnnotation(Class> annotation) {
153 | return addAnnotation(ClassName.get(annotation));
154 | }
155 |
156 | public Builder addModifiers(Modifier... modifiers) {
157 | Collections.addAll(this.modifiers, modifiers);
158 | return this;
159 | }
160 |
161 | public Builder addModifiers(Iterable modifiers) {
162 | checkNotNull(modifiers, "modifiers == null");
163 | for (Modifier modifier : modifiers) {
164 | this.modifiers.add(modifier);
165 | }
166 | return this;
167 | }
168 |
169 | public ParameterSpec build() {
170 | return new ParameterSpec(this);
171 | }
172 | }
173 | }
174 |
--------------------------------------------------------------------------------
/x2c-apt/src/main/java/com/squareup/javapoet/x2c/ParameterizedTypeName.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 Square, Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.squareup.javapoet.x2c;
17 |
18 | import java.io.IOException;
19 | import java.lang.reflect.Modifier;
20 | import java.lang.reflect.ParameterizedType;
21 | import java.lang.reflect.Type;
22 | import java.util.ArrayList;
23 | import java.util.Arrays;
24 | import java.util.LinkedHashMap;
25 | import java.util.List;
26 | import java.util.Map;
27 |
28 | import static com.squareup.javapoet.x2c.Util.checkArgument;
29 | import static com.squareup.javapoet.x2c.Util.checkNotNull;
30 |
31 | public final class ParameterizedTypeName extends TypeName {
32 | private final ParameterizedTypeName enclosingType;
33 | public final ClassName rawType;
34 | public final List typeArguments;
35 |
36 | ParameterizedTypeName(ParameterizedTypeName enclosingType, ClassName rawType,
37 | List typeArguments) {
38 | this(enclosingType, rawType, typeArguments, new ArrayList<>());
39 | }
40 |
41 | private ParameterizedTypeName(ParameterizedTypeName enclosingType, ClassName rawType,
42 | List typeArguments, List annotations) {
43 | super(annotations);
44 | this.rawType = checkNotNull(rawType, "rawType == null").annotated(annotations);
45 | this.enclosingType = enclosingType;
46 | this.typeArguments = Util.immutableList(typeArguments);
47 |
48 | checkArgument(!this.typeArguments.isEmpty() || enclosingType != null,
49 | "no type arguments: %s", rawType);
50 | for (TypeName typeArgument : this.typeArguments) {
51 | checkArgument(!typeArgument.isPrimitive() && typeArgument != VOID,
52 | "invalid type parameter: %s", typeArgument);
53 | }
54 | }
55 |
56 | @Override public ParameterizedTypeName annotated(List annotations) {
57 | return new ParameterizedTypeName(
58 | enclosingType, rawType, typeArguments, concatAnnotations(annotations));
59 | }
60 |
61 | @Override
62 | public TypeName withoutAnnotations() {
63 | return new ParameterizedTypeName(
64 | enclosingType, rawType.withoutAnnotations(), typeArguments, new ArrayList<>());
65 | }
66 |
67 | @Override CodeWriter emit(CodeWriter out) throws IOException {
68 | if (enclosingType != null) {
69 | enclosingType.emit(out);
70 | out.emit(".");
71 | if (isAnnotated()) {
72 | out.emit(" ");
73 | emitAnnotations(out);
74 | }
75 | out.emit(rawType.simpleName());
76 | } else {
77 | rawType.emit(out);
78 | }
79 | if (!typeArguments.isEmpty()) {
80 | out.emitAndIndent("<");
81 | boolean firstParameter = true;
82 | for (TypeName parameter : typeArguments) {
83 | if (!firstParameter) out.emitAndIndent(", ");
84 | parameter.emit(out);
85 | firstParameter = false;
86 | }
87 | out.emitAndIndent(">");
88 | }
89 | return out;
90 | }
91 |
92 | /**
93 | * Returns a new {@link ParameterizedTypeName} instance for the specified {@code name} as nested
94 | * inside this class.
95 | */
96 | public ParameterizedTypeName nestedClass(String name) {
97 | checkNotNull(name, "name == null");
98 | return new ParameterizedTypeName(this, rawType.nestedClass(name), new ArrayList<>(),
99 | new ArrayList<>());
100 | }
101 |
102 | /**
103 | * Returns a new {@link ParameterizedTypeName} instance for the specified {@code name} as nested
104 | * inside this class, with the specified {@code typeArguments}.
105 | */
106 | public ParameterizedTypeName nestedClass(String name, List typeArguments) {
107 | checkNotNull(name, "name == null");
108 | return new ParameterizedTypeName(this, rawType.nestedClass(name), typeArguments,
109 | new ArrayList<>());
110 | }
111 |
112 | /** Returns a parameterized type, applying {@code typeArguments} to {@code rawType}. */
113 | public static ParameterizedTypeName get(ClassName rawType, TypeName... typeArguments) {
114 | return new ParameterizedTypeName(null, rawType, Arrays.asList(typeArguments));
115 | }
116 |
117 | /** Returns a parameterized type, applying {@code typeArguments} to {@code rawType}. */
118 | public static ParameterizedTypeName get(Class> rawType, Type... typeArguments) {
119 | return new ParameterizedTypeName(null, ClassName.get(rawType), list(typeArguments));
120 | }
121 |
122 | /** Returns a parameterized type equivalent to {@code type}. */
123 | public static ParameterizedTypeName get(ParameterizedType type) {
124 | return get(type, new LinkedHashMap<>());
125 | }
126 |
127 | /** Returns a parameterized type equivalent to {@code type}. */
128 | static ParameterizedTypeName get(ParameterizedType type, Map map) {
129 | ClassName rawType = ClassName.get((Class>) type.getRawType());
130 | ParameterizedType ownerType = (type.getOwnerType() instanceof ParameterizedType)
131 | && !Modifier.isStatic(((Class>) type.getRawType()).getModifiers())
132 | ? (ParameterizedType) type.getOwnerType() : null;
133 | List typeArguments = TypeName.list(type.getActualTypeArguments(), map);
134 | return (ownerType != null)
135 | ? get(ownerType, map).nestedClass(rawType.simpleName(), typeArguments)
136 | : new ParameterizedTypeName(null, rawType, typeArguments);
137 | }
138 | }
139 |
--------------------------------------------------------------------------------
/x2c-apt/src/main/java/com/squareup/javapoet/x2c/TypeVariableName.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 Square, Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.squareup.javapoet.x2c;
17 |
18 | import java.io.IOException;
19 | import java.lang.reflect.Type;
20 | import java.util.ArrayList;
21 | import java.util.Arrays;
22 | import java.util.Collections;
23 | import java.util.LinkedHashMap;
24 | import java.util.List;
25 | import java.util.Map;
26 |
27 | import javax.lang.model.element.TypeParameterElement;
28 | import javax.lang.model.type.TypeMirror;
29 | import javax.lang.model.type.TypeVariable;
30 |
31 | import static com.squareup.javapoet.x2c.Util.checkArgument;
32 | import static com.squareup.javapoet.x2c.Util.checkNotNull;
33 |
34 | public final class TypeVariableName extends TypeName {
35 | public final String name;
36 | public final List bounds;
37 |
38 | private TypeVariableName(String name, List bounds) {
39 | this(name, bounds, new ArrayList<>());
40 | }
41 |
42 | private TypeVariableName(String name, List bounds, List annotations) {
43 | super(annotations);
44 | this.name = checkNotNull(name, "name == null");
45 | this.bounds = bounds;
46 |
47 | for (TypeName bound : this.bounds) {
48 | checkArgument(!bound.isPrimitive() && bound != VOID, "invalid bound: %s", bound);
49 | }
50 | }
51 |
52 | @Override public TypeVariableName annotated(List annotations) {
53 | return new TypeVariableName(name, bounds, annotations);
54 | }
55 |
56 | @Override public TypeName withoutAnnotations() {
57 | return new TypeVariableName(name, bounds);
58 | }
59 |
60 | public TypeVariableName withBounds(Type... bounds) {
61 | return withBounds(TypeName.list(bounds));
62 | }
63 |
64 | public TypeVariableName withBounds(TypeName... bounds) {
65 | return withBounds(Arrays.asList(bounds));
66 | }
67 |
68 | public TypeVariableName withBounds(List extends TypeName> bounds) {
69 | ArrayList newBounds = new ArrayList<>();
70 | newBounds.addAll(this.bounds);
71 | newBounds.addAll(bounds);
72 | return new TypeVariableName(name, newBounds, annotations);
73 | }
74 |
75 | private static TypeVariableName of(String name, List bounds) {
76 | // Strip java.lang.Object from bounds if it is present.
77 | List boundsNoObject = new ArrayList<>(bounds);
78 | boundsNoObject.remove(OBJECT);
79 | return new TypeVariableName(name, Collections.unmodifiableList(boundsNoObject));
80 | }
81 |
82 | @Override
83 | CodeWriter emit(CodeWriter out) throws IOException {
84 | emitAnnotations(out);
85 | return out.emitAndIndent(name);
86 | }
87 |
88 | /** Returns type variable named {@code name} without bounds. */
89 | public static TypeVariableName get(String name) {
90 | return TypeVariableName.of(name, Collections.emptyList());
91 | }
92 |
93 | /** Returns type variable named {@code name} with {@code bounds}. */
94 | public static TypeVariableName get(String name, TypeName... bounds) {
95 | return TypeVariableName.of(name, Arrays.asList(bounds));
96 | }
97 |
98 | /** Returns type variable named {@code name} with {@code bounds}. */
99 | public static TypeVariableName get(String name, Type... bounds) {
100 | return TypeVariableName.of(name, TypeName.list(bounds));
101 | }
102 |
103 | /** Returns type variable equivalent to {@code mirror}. */
104 | public static TypeVariableName get(TypeVariable mirror) {
105 | return get((TypeParameterElement) mirror.asElement());
106 | }
107 |
108 | /**
109 | * Make a TypeVariableName for the given TypeMirror. This form is used internally to avoid
110 | * infinite recursion in cases like {@code Enum>}. When we encounter such a
111 | * thing, we will make a TypeVariableName without bounds and add that to the {@code typeVariables}
112 | * map before looking up the bounds. Then if we encounter this TypeVariable again while
113 | * constructing the bounds, we can just return it from the map. And, the code that put the entry
114 | * in {@code variables} will make sure that the bounds are filled in before returning.
115 | */
116 | static TypeVariableName get(
117 | TypeVariable mirror, Map typeVariables) {
118 | TypeParameterElement element = (TypeParameterElement) mirror.asElement();
119 | TypeVariableName typeVariableName = typeVariables.get(element);
120 | if (typeVariableName == null) {
121 | // Since the bounds field is public, we need to make it an unmodifiableList. But we control
122 | // the List that that wraps, which means we can change it before returning.
123 | List bounds = new ArrayList<>();
124 | List visibleBounds = Collections.unmodifiableList(bounds);
125 | typeVariableName = new TypeVariableName(element.getSimpleName().toString(), visibleBounds);
126 | typeVariables.put(element, typeVariableName);
127 | for (TypeMirror typeMirror : element.getBounds()) {
128 | bounds.add(TypeName.get(typeMirror, typeVariables));
129 | }
130 | bounds.remove(OBJECT);
131 | }
132 | return typeVariableName;
133 | }
134 |
135 | /** Returns type variable equivalent to {@code element}. */
136 | public static TypeVariableName get(TypeParameterElement element) {
137 | String name = element.getSimpleName().toString();
138 | List extends TypeMirror> boundsMirrors = element.getBounds();
139 |
140 | List boundsTypeNames = new ArrayList<>();
141 | for (TypeMirror typeMirror : boundsMirrors) {
142 | boundsTypeNames.add(TypeName.get(typeMirror));
143 | }
144 |
145 | return TypeVariableName.of(name, boundsTypeNames);
146 | }
147 |
148 | /** Returns type variable equivalent to {@code type}. */
149 | public static TypeVariableName get(java.lang.reflect.TypeVariable> type) {
150 | return get(type, new LinkedHashMap<>());
151 | }
152 |
153 | /** @see #get(java.lang.reflect.TypeVariable, Map) */
154 | static TypeVariableName get(java.lang.reflect.TypeVariable> type,
155 | Map map) {
156 | TypeVariableName result = map.get(type);
157 | if (result == null) {
158 | List bounds = new ArrayList<>();
159 | List visibleBounds = Collections.unmodifiableList(bounds);
160 | result = new TypeVariableName(type.getName(), visibleBounds);
161 | map.put(type, result);
162 | for (Type bound : type.getBounds()) {
163 | bounds.add(TypeName.get(bound, map));
164 | }
165 | bounds.remove(OBJECT);
166 | }
167 | return result;
168 | }
169 | }
170 |
--------------------------------------------------------------------------------
/x2c-apt/src/main/java/com/squareup/javapoet/x2c/Util.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 Square, Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.squareup.javapoet.x2c;
17 |
18 | import java.util.ArrayList;
19 | import java.util.Arrays;
20 | import java.util.Collection;
21 | import java.util.Collections;
22 | import java.util.LinkedHashMap;
23 | import java.util.LinkedHashSet;
24 | import java.util.List;
25 | import java.util.Map;
26 | import java.util.Set;
27 |
28 | import javax.lang.model.element.Modifier;
29 |
30 | import static java.lang.Character.isISOControl;
31 |
32 | /**
33 | * Like Guava, but worse and standalone. This makes it easier to mix JavaPoet with libraries that
34 | * bring their own version of Guava.
35 | */
36 | final class Util {
37 | private Util() {
38 | }
39 |
40 | static Map> immutableMultimap(Map> multimap) {
41 | LinkedHashMap> result = new LinkedHashMap<>();
42 | for (Map.Entry> entry : multimap.entrySet()) {
43 | if (entry.getValue().isEmpty()) continue;
44 | result.put(entry.getKey(), immutableList(entry.getValue()));
45 | }
46 | return Collections.unmodifiableMap(result);
47 | }
48 |
49 | static Map immutableMap(Map map) {
50 | return Collections.unmodifiableMap(new LinkedHashMap<>(map));
51 | }
52 |
53 | static void checkArgument(boolean condition, String format, Object... args) {
54 | if (!condition) throw new IllegalArgumentException(String.format(format, args));
55 | }
56 |
57 | static T checkNotNull(T reference, String format, Object... args) {
58 | if (reference == null) throw new NullPointerException(String.format(format, args));
59 | return reference;
60 | }
61 |
62 | static void checkState(boolean condition, String format, Object... args) {
63 | if (!condition) throw new IllegalStateException(String.format(format, args));
64 | }
65 |
66 | static List immutableList(Collection collection) {
67 | return Collections.unmodifiableList(new ArrayList<>(collection));
68 | }
69 |
70 | static Set immutableSet(Collection set) {
71 | return Collections.unmodifiableSet(new LinkedHashSet<>(set));
72 | }
73 |
74 | static Set union(Set a, Set b) {
75 | Set result = new LinkedHashSet<>();
76 | result.addAll(a);
77 | result.addAll(b);
78 | return result;
79 | }
80 |
81 | static void requireExactlyOneOf(Set modifiers, Modifier... mutuallyExclusive) {
82 | int count = 0;
83 | for (Modifier modifier : mutuallyExclusive) {
84 | if (modifiers.contains(modifier)) count++;
85 | }
86 | checkArgument(count == 1, "modifiers %s must contain one of %s",
87 | modifiers, Arrays.toString(mutuallyExclusive));
88 | }
89 |
90 | static String characterLiteralWithoutSingleQuotes(char c) {
91 | // see https://docs.oracle.com/javase/specs/jls/se7/html/jls-3.html#jls-3.10.6
92 | switch (c) {
93 | case '\b': return "\\b"; /* \u0008: backspace (BS) */
94 | case '\t': return "\\t"; /* \u0009: horizontal tab (HT) */
95 | case '\n': return "\\n"; /* \u000a: linefeed (LF) */
96 | case '\f': return "\\f"; /* \u000c: form feed (FF) */
97 | case '\r': return "\\r"; /* \u000d: carriage return (CR) */
98 | case '\"': return "\""; /* \u0022: double quote (") */
99 | case '\'': return "\\'"; /* \u0027: single quote (') */
100 | case '\\': return "\\\\"; /* \u005c: backslash (\) */
101 | default:
102 | return isISOControl(c) ? String.format("\\u%04x", (int) c) : Character.toString(c);
103 | }
104 | }
105 |
106 | /** Returns the string literal representing {@code value}, including wrapping double quotes. */
107 | static String stringLiteralWithDoubleQuotes(String value, String indent) {
108 | StringBuilder result = new StringBuilder(value.length() + 2);
109 | result.append('"');
110 | for (int i = 0; i < value.length(); i++) {
111 | char c = value.charAt(i);
112 | // trivial case: single quote must not be escaped
113 | if (c == '\'') {
114 | result.append("'");
115 | continue;
116 | }
117 | // trivial case: double quotes must be escaped
118 | if (c == '\"') {
119 | result.append("\\\"");
120 | continue;
121 | }
122 | // default case: just let character literal do its work
123 | result.append(characterLiteralWithoutSingleQuotes(c));
124 | // need to append indent after linefeed?
125 | if (c == '\n' && i + 1 < value.length()) {
126 | result.append("\"\n").append(indent).append(indent).append("+ \"");
127 | }
128 | }
129 | result.append('"');
130 | return result.toString();
131 | }
132 | }
133 |
--------------------------------------------------------------------------------
/x2c-apt/src/main/java/com/squareup/javapoet/x2c/WildcardTypeName.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 Square, Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.squareup.javapoet.x2c;
17 |
18 | import java.io.IOException;
19 | import java.lang.reflect.Type;
20 | import java.lang.reflect.WildcardType;
21 | import java.util.ArrayList;
22 | import java.util.Collections;
23 | import java.util.LinkedHashMap;
24 | import java.util.List;
25 | import java.util.Map;
26 |
27 | import javax.lang.model.element.TypeParameterElement;
28 | import javax.lang.model.type.TypeMirror;
29 |
30 | import static com.squareup.javapoet.x2c.Util.checkArgument;
31 |
32 | public final class WildcardTypeName extends TypeName {
33 | public final List upperBounds;
34 | public final List lowerBounds;
35 |
36 | private WildcardTypeName(List upperBounds, List lowerBounds) {
37 | this(upperBounds, lowerBounds, new ArrayList<>());
38 | }
39 |
40 | private WildcardTypeName(List upperBounds, List lowerBounds,
41 | List annotations) {
42 | super(annotations);
43 | this.upperBounds = Util.immutableList(upperBounds);
44 | this.lowerBounds = Util.immutableList(lowerBounds);
45 |
46 | checkArgument(this.upperBounds.size() == 1, "unexpected extends bounds: %s", upperBounds);
47 | for (TypeName upperBound : this.upperBounds) {
48 | checkArgument(!upperBound.isPrimitive() && upperBound != VOID,
49 | "invalid upper bound: %s", upperBound);
50 | }
51 | for (TypeName lowerBound : this.lowerBounds) {
52 | checkArgument(!lowerBound.isPrimitive() && lowerBound != VOID,
53 | "invalid lower bound: %s", lowerBound);
54 | }
55 | }
56 |
57 | @Override public WildcardTypeName annotated(List annotations) {
58 | return new WildcardTypeName(upperBounds, lowerBounds, concatAnnotations(annotations));
59 | }
60 |
61 | @Override public TypeName withoutAnnotations() {
62 | return new WildcardTypeName(upperBounds, lowerBounds);
63 | }
64 |
65 | @Override
66 | CodeWriter emit(CodeWriter out) throws IOException {
67 | if (lowerBounds.size() == 1) {
68 | return out.emit("? super $T", lowerBounds.get(0));
69 | }
70 | return upperBounds.get(0).equals(TypeName.OBJECT)
71 | ? out.emit("?")
72 | : out.emit("? extends $T", upperBounds.get(0));
73 | }
74 |
75 | /**
76 | * Returns a type that represents an unknown type that extends {@code bound}. For example, if
77 | * {@code bound} is {@code CharSequence.class}, this returns {@code ? extends CharSequence}. If
78 | * {@code bound} is {@code Object.class}, this returns {@code ?}, which is shorthand for {@code
79 | * ? extends Object}.
80 | */
81 | public static WildcardTypeName subtypeOf(TypeName upperBound) {
82 | return new WildcardTypeName(Collections.singletonList(upperBound), Collections.emptyList());
83 | }
84 |
85 | public static WildcardTypeName subtypeOf(Type upperBound) {
86 | return subtypeOf(TypeName.get(upperBound));
87 | }
88 |
89 | /**
90 | * Returns a type that represents an unknown supertype of {@code bound}. For example, if {@code
91 | * bound} is {@code String.class}, this returns {@code ? super String}.
92 | */
93 | public static WildcardTypeName supertypeOf(TypeName lowerBound) {
94 | return new WildcardTypeName(Collections.singletonList(OBJECT),
95 | Collections.singletonList(lowerBound));
96 | }
97 |
98 | public static WildcardTypeName supertypeOf(Type lowerBound) {
99 | return supertypeOf(TypeName.get(lowerBound));
100 | }
101 |
102 | public static TypeName get(javax.lang.model.type.WildcardType mirror) {
103 | return get(mirror, new LinkedHashMap<>());
104 | }
105 |
106 | static TypeName get(
107 | javax.lang.model.type.WildcardType mirror,
108 | Map typeVariables) {
109 | TypeMirror extendsBound = mirror.getExtendsBound();
110 | if (extendsBound == null) {
111 | TypeMirror superBound = mirror.getSuperBound();
112 | if (superBound == null) {
113 | return subtypeOf(Object.class);
114 | } else {
115 | return supertypeOf(TypeName.get(superBound, typeVariables));
116 | }
117 | } else {
118 | return subtypeOf(TypeName.get(extendsBound, typeVariables));
119 | }
120 | }
121 |
122 | public static TypeName get(WildcardType wildcardName) {
123 | return get(wildcardName, new LinkedHashMap<>());
124 | }
125 |
126 | static TypeName get(WildcardType wildcardName, Map map) {
127 | return new WildcardTypeName(
128 | list(wildcardName.getUpperBounds(), map),
129 | list(wildcardName.getLowerBounds(), map));
130 | }
131 | }
132 |
--------------------------------------------------------------------------------
/x2c-apt/src/main/java/com/zhangyue/we/anoprocesser/FileFilter.java:
--------------------------------------------------------------------------------
1 | package com.zhangyue.we.anoprocesser;
2 |
3 | import java.io.File;
4 | import java.util.ArrayList;
5 | import java.util.HashMap;
6 |
7 | /**
8 | * @author chengwei 2018/9/7
9 | */
10 | public class FileFilter {
11 | private File mRoot;
12 | private ArrayList excludes;
13 | private ArrayList includes;
14 | private String mFileStart;
15 |
16 | public FileFilter(File root) {
17 | this.mRoot = root;
18 | }
19 |
20 | public FileFilter include(String include) {
21 | if (this.includes == null) {
22 | this.includes = new ArrayList();
23 | }
24 | this.includes.add(include);
25 | return this;
26 | }
27 |
28 | public FileFilter fileStart(String fileStart) {
29 | this.mFileStart = fileStart;
30 | return this;
31 | }
32 |
33 | public FileFilter exclude(String name) {
34 | if (excludes == null) {
35 | excludes = new ArrayList<>();
36 | }
37 | excludes.add(name);
38 | return this;
39 | }
40 |
41 | public HashMap> filter() {
42 | HashMap> map = new HashMap<>();
43 | filter(mRoot, map);
44 | return map;
45 | }
46 |
47 |
48 | private void filter(File dir, HashMap> map) {
49 | String dirName = dir.getName();
50 | ArrayList list;
51 | if (dir.isDirectory() && !isExclude(dirName)) {
52 | File[] files = dir.listFiles();
53 | boolean fitParent = isInclude(dirName);
54 | boolean fitFile;
55 | String fName;
56 | for (File f : files) {
57 | if (fitParent) {
58 | fName = f.getName();
59 | fitFile = mFileStart == null || fName.startsWith(mFileStart);
60 | if (!fitFile) {
61 | continue;
62 | }
63 | fName = fName.substring(0, fName.lastIndexOf("."));
64 | list = map.getOrDefault(fName, null);
65 | if (list == null) {
66 | list = new ArrayList<>();
67 | map.put(fName, list);
68 | }
69 | list.add(f);
70 | } else {
71 | filter(f, map);
72 | }
73 | }
74 | }
75 | }
76 |
77 | private boolean isExclude(String fName) {
78 | if (excludes == null) {
79 | return false;
80 | }
81 | for (String name : excludes) {
82 | if (fName.contains(name)) {
83 | return true;
84 | }
85 | }
86 | return false;
87 | }
88 |
89 | private boolean isInclude(String fName) {
90 | if (includes == null) {
91 | return false;
92 | }
93 | for (String name : includes) {
94 | if (fName.contains(name)) {
95 | return true;
96 | }
97 | }
98 | return false;
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/x2c-apt/src/main/java/com/zhangyue/we/anoprocesser/Log.java:
--------------------------------------------------------------------------------
1 | package com.zhangyue.we.anoprocesser;
2 |
3 | import javax.annotation.processing.Messager;
4 | import javax.tools.Diagnostic;
5 |
6 | /**
7 | * @author chengwei 2018/8/7
8 | */
9 | public class Log {
10 | private static Messager sMessager;
11 |
12 | public static void init(Messager msger) {
13 | sMessager = msger;
14 | }
15 |
16 | public static void w(String msg) {
17 | if (sMessager != null) {
18 | sMessager.printMessage(Diagnostic.Kind.OTHER, msg);
19 | }
20 | }
21 |
22 | public static void e(String msg) {
23 | if (sMessager != null) {
24 | sMessager.printMessage(Diagnostic.Kind.ERROR, msg);
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/x2c-apt/src/main/java/com/zhangyue/we/anoprocesser/Util.java:
--------------------------------------------------------------------------------
1 | package com.zhangyue.we.anoprocesser;
2 |
3 | import java.io.Closeable;
4 | import java.io.File;
5 | import java.util.ArrayList;
6 | import java.util.Collections;
7 | import java.util.Comparator;
8 |
9 | /**
10 | * @author chengwei 2018/9/7
11 | */
12 | public class Util {
13 |
14 | public static void close(Closeable closeable) {
15 | if (closeable != null) {
16 | try {
17 | closeable.close();
18 | } catch (Exception e) {
19 | e.printStackTrace();
20 | }
21 | }
22 | }
23 |
24 | public static String getDirName(File file) {
25 | return file.getParentFile().getName();
26 | }
27 |
28 | public static String getLayoutCategory(File file) {
29 | String name = file.getParentFile().getName();
30 | switch (name) {
31 | case "layout":
32 | return "";
33 | default:
34 | return name.substring(name.lastIndexOf("-") + 1);
35 | }
36 | }
37 |
38 | public static void sortLayout(ArrayList list) {
39 | if (list == null || list.size() <= 1) {
40 | return;
41 | }
42 |
43 | Collections.sort(list, new Comparator() {
44 | @Override
45 | public int compare(File file, File t1) {
46 | String sort1 = getLayoutCategory(file);
47 | String sort2 = getLayoutCategory(t1);
48 | if (sort1 == null || sort1.equals("")) {
49 | return 1;
50 | } else if (sort2 == null || sort2.equals("")) {
51 | return -1;
52 | } else if (sort1.equals("land")) {
53 | return -1;
54 | } else if (sort2.equals("land")) {
55 | return 1;
56 | } else {
57 | int v1 = Integer.parseInt(sort1.substring(sort1.indexOf("v") + 1));
58 | int v2 = Integer.parseInt(sort2.substring(sort2.indexOf("v") + 1));
59 | return v2 - v1;
60 | }
61 | }
62 | });
63 | }
64 |
65 |
66 | }
67 |
--------------------------------------------------------------------------------
/x2c-apt/src/main/java/com/zhangyue/we/anoprocesser/XmlProcessor.java:
--------------------------------------------------------------------------------
1 | package com.zhangyue.we.anoprocesser;
2 |
3 | import com.zhangyue.we.anoprocesser.xml.LayoutManager;
4 | import com.zhangyue.we.x2c.ano.Xml;
5 |
6 | import java.util.Set;
7 | import java.util.TreeSet;
8 |
9 | import javax.annotation.processing.AbstractProcessor;
10 | import javax.annotation.processing.ProcessingEnvironment;
11 | import javax.annotation.processing.RoundEnvironment;
12 | import javax.annotation.processing.SupportedAnnotationTypes;
13 | import javax.annotation.processing.SupportedSourceVersion;
14 | import javax.lang.model.SourceVersion;
15 | import javax.lang.model.element.Element;
16 | import javax.lang.model.element.PackageElement;
17 | import javax.lang.model.element.TypeElement;
18 |
19 | /**
20 | * @author chengwei 2018/8/7
21 | */
22 | @SupportedSourceVersion(SourceVersion.RELEASE_7)
23 | @SupportedAnnotationTypes("com.zhangyue.we.x2c.ano.Xml")
24 | public class XmlProcessor extends AbstractProcessor {
25 |
26 | private int mGroupId = 0;
27 | private LayoutManager mLayoutMgr;
28 |
29 | @Override
30 | public synchronized void init(ProcessingEnvironment processingEnvironment) {
31 | super.init(processingEnvironment);
32 | Log.init(processingEnvironment.getMessager());
33 | mLayoutMgr = LayoutManager.instance();
34 | mLayoutMgr.setFiler(processingEnvironment.getFiler());
35 | }
36 |
37 | @Override
38 | public boolean process(Set extends TypeElement> set, RoundEnvironment roundEnvironment) {
39 | Set extends Element> elements = roundEnvironment.getElementsAnnotatedWith(Xml.class);
40 | TreeSet layouts = new TreeSet<>();
41 | for (Element element : elements) {
42 | Xml xml = element.getAnnotation(Xml.class);
43 | String[] names = xml.layouts();
44 | for (String name : names) {
45 | layouts.add(name.substring(name.lastIndexOf(".") + 1));
46 | }
47 | }
48 |
49 | for (String name : layouts) {
50 | if (mGroupId == 0 && mLayoutMgr.getLayoutId(name) != null) {
51 | mGroupId = (mLayoutMgr.getLayoutId(name) >> 24);
52 | }
53 | mLayoutMgr.setGroupId(mGroupId);
54 | mLayoutMgr.translate(name);
55 | }
56 |
57 | mLayoutMgr.printTranslate();
58 | return false;
59 | }
60 |
61 |
62 | }
63 |
--------------------------------------------------------------------------------
/x2c-apt/src/main/java/com/zhangyue/we/anoprocesser/xml/Attr.java:
--------------------------------------------------------------------------------
1 | package com.zhangyue.we.anoprocesser.xml;
2 |
3 | import java.util.HashMap;
4 |
5 | /**
6 | * @author chengwei 2018/8/25
7 | */
8 | public class Attr implements Comparable {
9 |
10 | public String format;
11 | public String name;
12 | public HashMap enums = new HashMap<>();
13 | public Func toFunc;
14 |
15 |
16 | @Override
17 | public String toString() {
18 | return "Attr{" +
19 | "format='" + format + '\'' +
20 | ", name='" + name + '\'' +
21 | ", enums=" + enums +
22 | ", toFunc='" + toFunc + '\'' +
23 | '}';
24 | }
25 |
26 | @Override
27 | public int compareTo(Attr attr) {
28 | if (attr == null) {
29 | return 1;
30 | }
31 | if (attr.format == null && this.format != null) {
32 | return 1;
33 | }
34 | if (attr.enums.size() == 0 && this.enums.size() > 0) {
35 | return 1;
36 | }
37 |
38 | return 0;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/x2c-apt/src/main/java/com/zhangyue/we/anoprocesser/xml/Attr2FuncReader.java:
--------------------------------------------------------------------------------
1 | package com.zhangyue.we.anoprocesser.xml;
2 |
3 | import org.xml.sax.Attributes;
4 | import org.xml.sax.SAXException;
5 | import org.xml.sax.helpers.DefaultHandler;
6 |
7 | import java.io.File;
8 | import java.util.HashMap;
9 |
10 | import javax.xml.parsers.SAXParser;
11 | import javax.xml.parsers.SAXParserFactory;
12 |
13 | /**
14 | * @author chengwei 2018/8/25
15 | */
16 | public class Attr2FuncReader {
17 | private File mFile;
18 | private SAXParser mParser;
19 | private HashMap mAttr2Funcs = new HashMap<>();
20 |
21 | public Attr2FuncReader(File file) {
22 | this.mFile = file;
23 | }
24 |
25 | public HashMap parse() {
26 | try {
27 | this.mParser = SAXParserFactory.newInstance().newSAXParser();
28 | if (mFile.exists()) {
29 | mParser.parse(mFile, new Attr2FuncHandler());
30 | return new AttrReader(mFile.getParentFile(), mAttr2Funcs).parse();
31 | }
32 | } catch (Exception e) {
33 | e.printStackTrace();
34 | }
35 | return null;
36 | }
37 |
38 | private class Attr2FuncHandler extends DefaultHandler {
39 |
40 | private String mName;
41 | private String mToFunc;
42 |
43 | @Override
44 | public void startDocument() throws SAXException {
45 | super.startDocument();
46 | }
47 |
48 | @Override
49 | public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
50 | super.startElement(uri, localName, qName, attributes);
51 | mName = attributes.getValue("name");
52 | mToFunc = attributes.getValue("toFunc");
53 | }
54 |
55 | @Override
56 | public void endElement(String uri, String localName, String qName) throws SAXException {
57 | super.endElement(uri, localName, qName);
58 | mAttr2Funcs.put(mName, new Func(mToFunc.trim()));
59 | }
60 |
61 | @Override
62 | public void endDocument() throws SAXException {
63 | super.endDocument();
64 | mParser.reset();
65 | }
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/x2c-apt/src/main/java/com/zhangyue/we/anoprocesser/xml/AttrReader.java:
--------------------------------------------------------------------------------
1 | package com.zhangyue.we.anoprocesser.xml;
2 |
3 | import org.xml.sax.Attributes;
4 | import org.xml.sax.SAXException;
5 | import org.xml.sax.helpers.DefaultHandler;
6 |
7 | import java.io.File;
8 | import java.io.FileFilter;
9 | import java.io.IOException;
10 | import java.util.HashMap;
11 |
12 | import javax.xml.parsers.SAXParser;
13 | import javax.xml.parsers.SAXParserFactory;
14 |
15 | /**
16 | * @author chengwei 2018/8/25
17 | */
18 | public class AttrReader {
19 | private HashMap mAttrs = new HashMap<>();
20 | private File mFile;
21 | private SAXParser mParser;
22 | private HashMap mAttr2Funcs;
23 | /**
24 | * attName like "progress",but when we used in layout is "app:progress"
25 | * so we need a map
26 | */
27 | private HashMap mAttrNameMap = new HashMap<>();
28 |
29 | public AttrReader(File file, HashMap attr2Func) {
30 | this.mFile = getValueFile(file);
31 | this.mAttr2Funcs = attr2Func;
32 | for (String key : mAttr2Funcs.keySet()) {
33 | mAttrNameMap.put(key.substring(key.lastIndexOf(":") + 1), key);
34 | }
35 | try {
36 | this.mParser = SAXParserFactory.newInstance().newSAXParser();
37 | } catch (Exception e) {
38 | e.printStackTrace();
39 | }
40 | }
41 |
42 | private File getValueFile(File root) {
43 | File valueFile = null;
44 | String sep = File.separator;
45 | File valueDir = new File(root.getAbsolutePath() + sep + "build" + sep
46 | + "intermediates" + sep + "incremental");
47 | if (valueDir != null) {
48 | File[] filse = valueDir.listFiles(new FileFilter() {
49 | @Override
50 | public boolean accept(File file) {
51 | String fileName = file.getName();
52 | return fileName.startsWith("merge") && fileName.endsWith("Resources");
53 | }
54 | });
55 | long maxTime = 0;
56 |
57 | File tmp;
58 | for (File f : filse) {
59 |
60 | tmp = new File(f.getAbsolutePath() + sep + "merged.dir" + sep + "values" + sep + "values.xml");
61 | if (tmp.lastModified() > maxTime) {
62 | maxTime = tmp.lastModified();
63 | valueFile = tmp;
64 | }
65 | }
66 | }
67 | if (valueFile == null) {
68 | valueFile = new File(root.getAbsolutePath() + sep + "src" + sep + "main" + sep + "res" + sep + "values"
69 | + sep + "attrs.xml");
70 | }
71 |
72 | return valueFile;
73 | }
74 |
75 | public HashMap parse() {
76 | try {
77 | mParser.parse(mFile, new AttrHandler());
78 | } catch (SAXException e) {
79 | e.printStackTrace();
80 | } catch (IOException e) {
81 | e.printStackTrace();
82 | }
83 | return mAttrs;
84 | }
85 |
86 | private class AttrHandler extends DefaultHandler {
87 |
88 | private Attr mAttr;
89 |
90 | @Override
91 | public void startDocument() throws SAXException {
92 | super.startDocument();
93 | }
94 |
95 | @Override
96 | public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
97 | super.startElement(uri, localName, qName, attributes);
98 | String name = attributes.getValue("name");
99 | if (qName.equals("attr")) {
100 | if (mAttrNameMap.containsKey(name)) {
101 | mAttr = new Attr();
102 | mAttr.name = mAttrNameMap.get(name);
103 | mAttr.format = attributes.getValue("format");
104 | mAttr.toFunc = mAttr2Funcs.get(mAttrNameMap.get(name));
105 | } else {
106 | mAttr = null;
107 | }
108 | } else if (qName.equals("enum") || qName.equals("flag")) {
109 | if (mAttr != null) {
110 | mAttr.enums.put(name, attributes.getValue("value"));
111 | }
112 | } else {
113 | mAttr = null;
114 | }
115 | }
116 |
117 | @Override
118 | public void endElement(String uri, String localName, String qName) throws SAXException {
119 | super.endElement(uri, localName, qName);
120 | if (qName.equals("attr")) {
121 | if (mAttr != null) {
122 | Attr oth = mAttrs.get(mAttr.name);
123 | if (mAttr.compareTo(oth) > 0) {
124 | mAttrs.put(mAttr.name, mAttr);
125 | }
126 | }
127 | mAttr = null;
128 | }
129 | }
130 |
131 | }
132 | }
133 |
--------------------------------------------------------------------------------
/x2c-apt/src/main/java/com/zhangyue/we/anoprocesser/xml/Func.java:
--------------------------------------------------------------------------------
1 | package com.zhangyue.we.anoprocesser.xml;
2 |
3 | /**
4 | * @author chengwei 2018/8/25
5 | */
6 | public class Func {
7 |
8 | public String name;
9 | public boolean isView;
10 | public String paramsType;
11 |
12 | public Func(String toFunc) {
13 | String[] ss = toFunc.split("\\.");
14 | if (ss.length == 2) {
15 | isView = ss[0].equalsIgnoreCase("view");
16 | int index = ss[1].indexOf("=");
17 | if (index > 0) {
18 | paramsType = ss[1].substring(index + 1);
19 | name = "%s." + ss[1].substring(0, index + 1) + "%s";
20 | } else {
21 | index = ss[1].indexOf("(");
22 | int indexQot = ss[1].indexOf(")");
23 | paramsType = ss[1].substring(ss[1].indexOf("(") + 1, ss[1].indexOf(")"));
24 | name = "%s." + ss[1].substring(0, index + 1) + "%s" + ss[1].substring(indexQot);
25 | }
26 | if (!name.endsWith(";")) {
27 | name += ";";
28 | }
29 | }
30 | }
31 |
32 |
33 | @Override
34 | public String toString() {
35 | return "Func{" +
36 | "name='" + name + '\'' +
37 | ", isView=" + isView +
38 | ", paramsType='" + paramsType + '\'' +
39 | '}';
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/x2c-apt/src/main/java/com/zhangyue/we/anoprocesser/xml/LayoutReader.java:
--------------------------------------------------------------------------------
1 | package com.zhangyue.we.anoprocesser.xml;
2 |
3 | import com.zhangyue.we.anoprocesser.Util;
4 | import com.zhangyue.we.view.View;
5 |
6 | import org.xml.sax.Attributes;
7 | import org.xml.sax.SAXException;
8 | import org.xml.sax.helpers.DefaultHandler;
9 |
10 | import java.io.File;
11 | import java.util.Stack;
12 |
13 | import javax.annotation.processing.Filer;
14 | import javax.xml.parsers.SAXParser;
15 | import javax.xml.parsers.SAXParserFactory;
16 |
17 | /**
18 | * @author chengwei 2018/8/7
19 | */
20 | public class LayoutReader {
21 | private Filer mFiler;
22 | private SAXParser mParser;
23 | private String mName;
24 | private String mFullName;
25 | private String mLayoutName;
26 | private String mPackageName;
27 | private File mFile;
28 |
29 | public LayoutReader(File file, String name, Filer filer, String packageName, int groupId) {
30 | mFile = file;
31 | mFiler = filer;
32 | mPackageName = packageName;
33 | mLayoutName = name;
34 | mName = getJavaName(groupId, name);
35 | }
36 |
37 | public String parse() {
38 | try {
39 | mParser = SAXParserFactory.newInstance().newSAXParser();
40 | mParser.parse(mFile, new XmlHandler());
41 | } catch (Exception e) {
42 | e.printStackTrace();
43 | }
44 | return mFullName;
45 | }
46 |
47 | private class XmlHandler extends DefaultHandler {
48 | private Stack mStack;
49 | private View mRootView;
50 | private boolean isDataBinding;
51 |
52 | @Override
53 | public void startDocument() throws SAXException {
54 | super.startDocument();
55 | mStack = new Stack<>();
56 | }
57 |
58 | @Override
59 | public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
60 | View view = createView(qName, attributes);
61 | if (view != null) {
62 | if (mStack.size() > 0) {
63 | view.setParent(mStack.get(mStack.size() - 1));
64 | } else {
65 | view.setParent(null);
66 | }
67 | mStack.push(view);
68 | }
69 | super.startElement(uri, localName, qName, attributes);
70 | }
71 |
72 | @Override
73 | public void endElement(String uri, String localName, String qName) throws SAXException {
74 | super.endElement(uri, localName, qName);
75 |
76 | if (mStack.size() > 0) {
77 | View view = mStack.pop();
78 | if (mStack.size() == 0) {
79 | mRootView = view;
80 | StringBuilder stringBuilder = new StringBuilder();
81 | mRootView.translate(stringBuilder);
82 | stringBuilder.append("return ").append(mRootView.getObjName());
83 | LayoutWriter writer = new LayoutWriter(stringBuilder.toString(), mFiler, mName, mPackageName
84 | , Util.getLayoutCategory(mFile), mLayoutName, mRootView.getImports());
85 | mFullName = writer.write();
86 | }
87 | }
88 | }
89 |
90 | @Override
91 | public void endDocument() throws SAXException {
92 | super.endDocument();
93 | }
94 |
95 | private View createView(String name, Attributes attributes) {
96 | if (name.equals("layout") || name.equals("data") || name.equals("variable")|| name.equals("import")) {
97 | isDataBinding = true;
98 | return null;
99 | }
100 | View view = new View(mPackageName, name, attributes);
101 | if (mStack.size() == 0) {
102 | view.setDirName(Util.getDirName(mFile));
103 | view.setIsDataBinding(isDataBinding);
104 | }
105 | view.setLayoutName(mLayoutName);
106 | return view;
107 | }
108 | }
109 |
110 |
111 | private String getJavaName(int groupId, String name) {
112 | String retName = groupId + "_" + name;
113 | String[] ss = retName.split("_");
114 | StringBuilder stringBuilder = new StringBuilder("X2C");
115 | for (int i = 0; i < ss.length; i++) {
116 | stringBuilder.append(ss[i].substring(0, 1).toUpperCase())
117 | .append(ss[i].substring(1));
118 | if (i < ss.length - 1) {
119 | stringBuilder.append("_");
120 | }
121 | }
122 | return stringBuilder.toString();
123 | }
124 |
125 |
126 | }
127 |
--------------------------------------------------------------------------------
/x2c-apt/src/main/java/com/zhangyue/we/anoprocesser/xml/LayoutWriter.java:
--------------------------------------------------------------------------------
1 | package com.zhangyue.we.anoprocesser.xml;
2 |
3 | import com.squareup.javapoet.x2c.ClassName;
4 | import com.squareup.javapoet.x2c.MethodSpec;
5 | import com.squareup.javapoet.x2c.TypeSpec;
6 | import com.squareup.javapoet.x2c.JavaFile;
7 |
8 | import java.io.IOException;
9 | import java.util.TreeSet;
10 |
11 | import javax.annotation.processing.Filer;
12 | import javax.lang.model.element.Modifier;
13 |
14 | /**
15 | * @author chengwei 2018/8/8
16 | */
17 | public class LayoutWriter {
18 | private Filer mFiler;
19 | private String mName;
20 | private String mMethodSpec;
21 | private String mPkgName;
22 | private String mLayoutCategory;
23 | private String mLayoutName;
24 | private TreeSet mImports;
25 |
26 | public LayoutWriter(String methodSpec, Filer filer, String javaName
27 | , String pkgName
28 | , String layoutSort
29 | , String layoutName
30 | , TreeSet imports) {
31 | this.mMethodSpec = methodSpec;
32 | this.mFiler = filer;
33 | this.mName = javaName;
34 | this.mPkgName = pkgName;
35 | this.mLayoutCategory = layoutSort;
36 | this.mLayoutName = layoutName;
37 | this.mImports = imports;
38 | }
39 |
40 | public String write() {
41 |
42 | MethodSpec methodSpec = MethodSpec.methodBuilder("createView")
43 | .addParameter(ClassName.get("android.content", "Context"), "ctx")
44 | .addStatement(mMethodSpec)
45 | .returns(ClassName.get("android.view", "View"))
46 | .addAnnotation(Override.class)
47 | .addModifiers(Modifier.PUBLIC)
48 | .build();
49 |
50 | TypeSpec typeSpec = TypeSpec.classBuilder(mName)
51 | .addMethod(methodSpec)
52 | .addSuperinterface(ClassName.get("com.zhangyue.we.x2c", "IViewCreator"))
53 | .addModifiers(Modifier.PUBLIC)
54 | .addJavadoc(String.format("WARN!!! dont edit this file\ntranslate from {@link %s.R.layout.%s}" +
55 | "\nautho chengwei \nemail chengwei@zhangyue.com\n", mPkgName, mLayoutName))
56 | .build();
57 |
58 | String pkgName = "com.zhangyue.we.x2c.layouts";
59 | if (mLayoutCategory != null && mLayoutCategory.length() > 0) {
60 | pkgName += ("." + mLayoutCategory);
61 | }
62 | JavaFile javaFile = JavaFile.builder(pkgName, typeSpec)
63 | .addImports(mImports)
64 | .build();
65 | try {
66 | javaFile.writeTo(mFiler);
67 | } catch (IOException e) {
68 | e.printStackTrace();
69 | }
70 |
71 | return pkgName + "." + mName;
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/x2c-apt/src/main/java/com/zhangyue/we/anoprocesser/xml/MapWriter.java:
--------------------------------------------------------------------------------
1 | package com.zhangyue.we.anoprocesser.xml;
2 |
3 | import com.squareup.javapoet.x2c.ClassName;
4 | import com.squareup.javapoet.x2c.MethodSpec;
5 | import com.squareup.javapoet.x2c.TypeSpec;
6 | import com.squareup.javapoet.x2c.JavaFile;
7 | import com.zhangyue.we.anoprocesser.Util;
8 |
9 | import java.io.File;
10 | import java.io.IOException;
11 | import java.util.ArrayList;
12 | import java.util.TreeSet;
13 |
14 | import javax.annotation.processing.Filer;
15 | import javax.lang.model.element.Modifier;
16 |
17 | /**
18 | * @author chengwei 2018/8/9
19 | */
20 | public class MapWriter {
21 |
22 | private int mGroupId;
23 | private ArrayList mLayouts;
24 | private ArrayList mJavaNames;
25 | private Filer mFiler;
26 |
27 | MapWriter(int groupId, ArrayList layouts, ArrayList javaNames, Filer filer) {
28 | this.mGroupId = groupId;
29 | this.mLayouts = layouts;
30 | this.mJavaNames = javaNames;
31 | this.mFiler = filer;
32 | }
33 |
34 | public void write() {
35 | if (mJavaNames == null || mJavaNames.size() == 0 || mLayouts == null || mLayouts.size() == 0) {
36 | return;
37 | }
38 | TreeSet imports = new TreeSet<>();
39 | StringBuilder stringBuilder = new StringBuilder();
40 | if (mLayouts.size() == 1 && mJavaNames.size() == 1) {
41 | stringBuilder.append(String.format("return new %s().createView(context)", mJavaNames.get(0)));
42 | } else {
43 | stringBuilder.append("View view = null ;");
44 | stringBuilder.append("\nint sdk = Build.VERSION.SDK_INT;");
45 | imports.add("android.os.Build");
46 | for (int i = 0; i < mJavaNames.size(); i++) {
47 | if (i == mJavaNames.size() - 1) {
48 | stringBuilder.append(" else {");
49 |
50 | } else {
51 | String layoutCategory = Util.getLayoutCategory(mLayouts.get(i));
52 | if (layoutCategory.equals("land")) {
53 | stringBuilder.append("\nint orientation = context.getResources().getConfiguration().orientation;");
54 | stringBuilder.append("\nboolean isLandscape = orientation == Configuration.ORIENTATION_LANDSCAPE;");
55 | stringBuilder.append("\nif (isLandscape) {");
56 | imports.add("android.content.res.Configuration");
57 | } else if (layoutCategory.startsWith("v")) {
58 | String sdk = layoutCategory.substring(layoutCategory.lastIndexOf("v") + 1);
59 | stringBuilder.append(String.format(" else if (sdk >= %s) {", sdk));
60 | }
61 | }
62 | stringBuilder.append(String.format("\n\tview = new %s().createView(context);\n}", mJavaNames.get(i)));
63 | }
64 | stringBuilder.append("\nreturn view");
65 | }
66 |
67 | MethodSpec methodSpec = MethodSpec.methodBuilder("createView")
68 | .addParameter(ClassName.get("android.content", "Context"), "context")
69 | .addStatement(stringBuilder.toString())
70 | .returns(ClassName.get("android.view", "View"))
71 | .addAnnotation(Override.class)
72 | .addModifiers(Modifier.PUBLIC)
73 | .build();
74 |
75 | String name = mLayouts.get(0).getName().substring(0, mLayouts.get(0).getName().indexOf("."));
76 | TypeSpec typeSpec = TypeSpec.classBuilder(String.format("X2C%s_%s", mGroupId, name))
77 | .addSuperinterface(ClassName.get("com.zhangyue.we.x2c", "IViewCreator"))
78 | .addModifiers(Modifier.PUBLIC)
79 | .addMethod(methodSpec)
80 | .addJavadoc(String.format("WARN!!! don't edit this file\n" +
81 | "\nauthor chengwei \nemail chengwei@zhangyue.com\n"))
82 | .build();
83 |
84 | JavaFile javaFile = JavaFile.builder("com.zhangyue.we.x2c", typeSpec)
85 | .addImports(imports)
86 | .build();
87 | try {
88 | javaFile.writeTo(mFiler);
89 | } catch (IOException e) {
90 | e.printStackTrace();
91 | }
92 | }
93 |
94 | }
95 |
--------------------------------------------------------------------------------
/x2c-apt/src/main/java/com/zhangyue/we/anoprocesser/xml/Style.java:
--------------------------------------------------------------------------------
1 | package com.zhangyue.we.anoprocesser.xml;
2 |
3 | import java.util.HashMap;
4 |
5 | /**
6 | * @author chengwei 2018/8/15
7 | */
8 | public class Style {
9 | public String name;
10 | public String parent;
11 | public HashMap attribute = new HashMap<>();
12 | }
13 |
--------------------------------------------------------------------------------
/x2c-apt/src/main/java/com/zhangyue/we/anoprocesser/xml/StyleReader.java:
--------------------------------------------------------------------------------
1 | package com.zhangyue.we.anoprocesser.xml;
2 |
3 | import com.zhangyue.we.anoprocesser.FileFilter;
4 | import com.zhangyue.we.anoprocesser.Log;
5 |
6 | import org.xml.sax.Attributes;
7 | import org.xml.sax.SAXException;
8 | import org.xml.sax.helpers.DefaultHandler;
9 |
10 | import java.io.File;
11 | import java.util.ArrayList;
12 | import java.util.HashMap;
13 |
14 | import javax.xml.parsers.SAXParser;
15 | import javax.xml.parsers.SAXParserFactory;
16 |
17 | /**
18 | * @author chengwei 2018/8/15
19 | */
20 | public class StyleReader {
21 | private HashMap mStyles;
22 | private File mRootFile;
23 | private SAXParser mParser;
24 |
25 | public StyleReader(File file, HashMap styles) {
26 | this.mRootFile = file;
27 | this.mStyles = styles;
28 | try {
29 | this.mParser = SAXParserFactory.newInstance().newSAXParser();
30 | } catch (Exception e) {
31 | e.printStackTrace();
32 | }
33 |
34 | }
35 |
36 | public void parse() {
37 | HashMap> styles = scanStyles(mRootFile);
38 | Log.w("parse "+mRootFile.getAbsolutePath());
39 | for (ArrayList list : styles.values()) {
40 | for (File file : list) {
41 | try {
42 | Log.w("style "+file.getAbsolutePath());
43 | mParser.parse(file, new StyleHandler());
44 | } catch (Exception e) {
45 | e.printStackTrace();
46 | }
47 | }
48 | }
49 | }
50 |
51 | private HashMap> scanStyles(File root) {
52 | return new FileFilter(root)
53 | .include("values")
54 | .fileStart("style")
55 | .exclude("layout")
56 | .exclude("build")
57 | .exclude("java")
58 | .exclude("libs")
59 | .exclude("mipmap")
60 | .exclude("drawable")
61 | .exclude("anim")
62 | .exclude("color")
63 | .exclude("menu")
64 | .exclude("raw")
65 | .exclude("xml")
66 | .filter();
67 | }
68 |
69 |
70 | private class StyleHandler extends DefaultHandler {
71 |
72 | private Style mStyle;
73 | private String mName;
74 | private String mQname;
75 |
76 | @Override
77 | public void startDocument() throws SAXException {
78 | super.startDocument();
79 | }
80 |
81 | @Override
82 | public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
83 | super.startElement(uri, localName, qName, attributes);
84 | mName = attributes.getValue("name");
85 | if (qName.equals("style")) {
86 | mStyle = new Style();
87 | mStyle.name = mName;
88 | mStyle.parent = attributes.getValue("parent");
89 | if (mStyle.parent == null && mName.contains(".")) {
90 | mStyle.parent = mName.substring(0, mName.lastIndexOf("."));
91 | }
92 | } else if (qName.equals("item")) {
93 | mStyle.attribute.put(mName, localName);
94 | }
95 |
96 | this.mQname = qName;
97 |
98 | }
99 |
100 |
101 | @Override
102 | public void characters(char[] ch, int start, int length) throws SAXException {
103 | super.characters(ch, start, length);
104 | if (mQname != null) {
105 | String value = "";
106 | try {
107 | value = new String(ch, start, length);
108 | } catch (Exception e) {
109 | e.printStackTrace();
110 | }
111 | if (mStyle != null) {
112 | mStyle.attribute.put(mName, value);
113 | }
114 | }
115 | mQname = null;
116 | }
117 |
118 |
119 | @Override
120 | public void endElement(String uri, String localName, String qName) throws SAXException {
121 | super.endElement(uri, localName, qName);
122 | if (qName.equals("style")) {
123 | mStyles.put(mStyle.name, mStyle);
124 | mStyle = null;
125 | }
126 | }
127 |
128 | @Override
129 | public void endDocument() throws SAXException {
130 | super.endDocument();
131 | }
132 | }
133 |
134 | }
135 |
--------------------------------------------------------------------------------
/x2c-apt/src/main/java/com/zhangyue/we/view/CustomAttr.java:
--------------------------------------------------------------------------------
1 | package com.zhangyue.we.view;
2 |
3 | import com.zhangyue.we.anoprocesser.xml.Attr;
4 | import com.zhangyue.we.anoprocesser.xml.LayoutManager;
5 |
6 | import java.util.HashMap;
7 | import java.util.TreeSet;
8 |
9 | /**
10 | * @author chengwei 2018/8/25
11 | */
12 | public class CustomAttr implements ITranslator {
13 |
14 | private TreeSet mImports;
15 | private String mView;
16 | private String mLayoutParams;
17 | private HashMap mAttrs;
18 |
19 | public CustomAttr(TreeSet imports, String layoutParams, String view) {
20 | this.mImports = imports;
21 | this.mView = view;
22 | this.mLayoutParams = layoutParams;
23 | this.mAttrs = LayoutManager.instance().getAttrs();
24 | }
25 |
26 |
27 | @Override
28 | public boolean translate(StringBuilder stringBuilder, String key, String value) {
29 | if (mAttrs == null || mAttrs.size() == 0) {
30 | return false;
31 | }
32 | Attr attr = mAttrs.get(key);
33 | if (attr != null) {
34 | if (attr.toFunc != null && attr.toFunc.name != null) {
35 | stringBuilder.append(String.format(attr.toFunc.name + "\n", attr.toFunc.isView ? mView : mLayoutParams
36 | , getValue(attr, value)));
37 | }
38 |
39 | return true;
40 | }
41 | return false;
42 | }
43 |
44 | private String getValue(Attr attr, String value) {
45 | String[] ss = value.split("\\|");
46 | StringBuilder ret = new StringBuilder();
47 | for (int i = 0; i < ss.length; i++) {
48 | ret.append(getSingleValue(attr, ss[i]));
49 | if (i < ss.length - 1) {
50 | ret.append("|");
51 | }
52 | }
53 | return ret.toString();
54 | }
55 |
56 | private String getSingleValue(Attr attr, String value) {
57 | String ret = attr.enums.get(value);
58 | if (ret != null) {
59 | return ret;
60 | }
61 |
62 | if (value.startsWith("@drawable/")) {
63 | return "R.drawable." + value.substring(value.indexOf("/") + 1);
64 | } else if (value.startsWith("@mipmap/")) {
65 | return "R.mipmap." + value.substring(value.indexOf("/") + 1);
66 | } else if (value.startsWith("@color/") || value.startsWith("#")) {
67 | return View.getColor(value);
68 | } else if (value.startsWith("@id/") || value.startsWith("@+id/")) {
69 | return "R.id." + value.substring(value.indexOf("/") + 1);
70 | } else if (value.startsWith("@dimen/")
71 | || value.endsWith("dp")
72 | || value.endsWith("dip")
73 | || value.endsWith("dip")
74 | || value.endsWith("px")
75 | || value.endsWith("sp")) {
76 | return View.getDimen(value);
77 | } else if (value.startsWith("@string/")) {
78 | return View.getString(value);
79 | } else if (value.startsWith("@anim/")) {
80 | return "R.anim." + value.substring(value.indexOf("/") + 1);
81 | } else if (value.startsWith("@layout/")) {
82 | return "R.layout." + value.substring(value.indexOf("/") + 1);
83 | } else {
84 | switch (attr.toFunc.paramsType.toLowerCase()) {
85 | case "float":
86 | return value + "f";
87 | case "string":
88 | return "\"" + value + "\"";
89 | default:
90 | return value;
91 | }
92 | }
93 | }
94 |
95 | @Override
96 | public void onAttributeEnd(StringBuilder stringBuilder) {
97 |
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/x2c-apt/src/main/java/com/zhangyue/we/view/ITranslator.java:
--------------------------------------------------------------------------------
1 | package com.zhangyue.we.view;
2 |
3 | /**
4 | * @author chengwei 2018/8/23
5 | */
6 | public interface ITranslator {
7 | boolean translate(StringBuilder stringBuilder, String key, String value);
8 | void onAttributeEnd(StringBuilder stringBuilder);
9 | }
10 |
--------------------------------------------------------------------------------
/x2c-apt/src/main/java/com/zhangyue/we/x2c/ano/Xml.java:
--------------------------------------------------------------------------------
1 | package com.zhangyue.we.x2c.ano;
2 |
3 | import java.lang.annotation.ElementType;
4 | import java.lang.annotation.Retention;
5 | import java.lang.annotation.RetentionPolicy;
6 | import java.lang.annotation.Target;
7 |
8 | /**
9 | * @author chengwei 2018/8/7
10 | */
11 |
12 | @Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.LOCAL_VARIABLE})
13 | @Retention(RetentionPolicy.SOURCE)
14 | public @interface Xml {
15 |
16 | String[] layouts();
17 | }
18 |
--------------------------------------------------------------------------------
/x2c-apt/src/main/resources/META-INF/services/javax.annotation.processing.Processor:
--------------------------------------------------------------------------------
1 | com.zhangyue.we.anoprocesser.XmlProcessor
--------------------------------------------------------------------------------
/x2c-binding/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/x2c-binding/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | compileSdkVersion 28
5 |
6 |
7 |
8 | defaultConfig {
9 | minSdkVersion 15
10 | targetSdkVersion 28
11 | versionCode 1
12 | versionName "1.0"
13 |
14 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
15 |
16 | }
17 |
18 | buildTypes {
19 | release {
20 | minifyEnabled false
21 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
22 | }
23 | }
24 |
25 | }
26 |
27 | dependencies {
28 | implementation fileTree(include: ['*.jar'], dir: 'libs')
29 | compileOnly fileTree(include: ['*.jar'], dir: 'libs-provided')
30 | }
31 |
32 |
33 |
34 |
35 | apply plugin: 'com.github.dcendents.android-maven'
36 | apply plugin: 'com.jfrog.bintray'
37 |
38 | //项目主页
39 | def siteUrl = 'https://github.com/chengweidev' // project homepage
40 | //项目的版本控制地址
41 | def gitUrl = 'https://github.com/chengweidev' // project git
42 |
43 | //发布到组织名称名字,必须填写
44 | group = "com.zhangyue.we"
45 | //发布到JCenter上的项目名字,必须填写
46 | def libName = "x2c-binding"
47 | // 版本号,下次更新是只需要更改版本号即可
48 | version = "1.0.5"
49 |
50 | //生成源文件
51 | task sourcesJar(type: Jar) {
52 | from android.sourceSets.main.java.srcDirs
53 | classifier = 'sources'
54 | }
55 | //生成文档
56 | task javadoc(type: Javadoc) {
57 | source = android.sourceSets.main.java.srcDirs
58 | classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
59 | options.encoding "UTF-8"
60 | options.charSet 'UTF-8'
61 | options.author true
62 | options.version true
63 | options.links "https://github.com/chengweidev"
64 | failOnError false
65 | }
66 |
67 | //文档打包成jar
68 | task javadocJar(type: Jar, dependsOn: javadoc) {
69 | classifier = 'javadoc'
70 | from javadoc.destinationDir
71 | }
72 | //拷贝javadoc文件
73 | task copyDoc(type: Copy) {
74 | from "${buildDir}/docs/"
75 | into "docs"
76 | }
77 |
78 | //上传到jcenter所需要的源码文件
79 | artifacts {
80 | archives javadocJar
81 | archives sourcesJar
82 | }
83 |
84 | // 配置maven库,生成POM.xml文件
85 | install {
86 | repositories.mavenInstaller {
87 | // This generates POM.xml with proper parameters
88 | pom {
89 | project {
90 | packaging 'aar'
91 | name 'xml 2 code libraray'
92 | url siteUrl
93 | licenses {
94 | license {
95 | name 'xml 2 code libraray'
96 | url 'https://github.com/chengweidev'
97 | }
98 | }
99 | developers {
100 | developer {
101 | id 'chengweidev'
102 | name 'chengweidev'
103 | email 'chengweidev@gmail.com'
104 | }
105 | }
106 | scm {
107 | connection gitUrl
108 | developerConnection gitUrl
109 | url siteUrl
110 | }
111 | }
112 | }
113 | }
114 | }
115 |
116 | //上传到jcenter
117 | Properties properties = new Properties()
118 | properties.load(project.rootProject.file('local.properties').newDataInputStream())
119 | bintray {
120 | user = properties.getProperty("bintray.user") //读取 local.properties 文件里面的 bintray.user
121 | key = properties.getProperty("bintray.apikey") //读取 local.properties 文件里面的 bintray.apikey
122 | configurations = ['archives']
123 | pkg {
124 | repo = "maven"
125 | name = libName //发布到JCenter上的项目名字,必须填写
126 | desc = 'xml to code' //项目描述
127 | websiteUrl = siteUrl
128 | vcsUrl = gitUrl
129 | licenses = ["Apache-2.0"]
130 | publish = true
131 | }
132 | }
--------------------------------------------------------------------------------
/x2c-binding/libs-provided/databinding.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iReaderAndroid/X2C/9bdf7ea7bc509481ce9fd1d1ea69b6847b5f832e/x2c-binding/libs-provided/databinding.jar
--------------------------------------------------------------------------------
/x2c-binding/libs-provided/x2c.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iReaderAndroid/X2C/9bdf7ea7bc509481ce9fd1d1ea69b6847b5f832e/x2c-binding/libs-provided/x2c.jar
--------------------------------------------------------------------------------
/x2c-binding/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/x2c-binding/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/x2c-binding/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | sup-databinding
3 |
4 |
--------------------------------------------------------------------------------
/x2c-lib/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/x2c-lib/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | compileSdkVersion 28
5 |
6 | defaultConfig {
7 | minSdkVersion 15
8 | targetSdkVersion 28
9 | versionCode 1
10 | versionName "1.0"
11 |
12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
13 | javaCompileOptions {
14 | annotationProcessorOptions.includeCompileClasspath = true
15 | }
16 | }
17 |
18 | buildTypes {
19 | release {
20 | minifyEnabled false
21 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
22 | }
23 | }
24 |
25 | }
26 |
27 | dependencies {
28 | implementation fileTree(dir: 'libs', include: ['*.jar'])
29 | }
30 |
31 |
32 | apply plugin: 'com.github.dcendents.android-maven'
33 | apply plugin: 'com.jfrog.bintray'
34 |
35 | //项目主页
36 | def siteUrl = 'https://github.com/chengweidev' // project homepage
37 | //项目的版本控制地址
38 | def gitUrl = 'https://github.com/chengweidev' // project git
39 |
40 | //发布到组织名称名字,必须填写
41 | group = "com.zhangyue.we"
42 | //发布到JCenter上的项目名字,必须填写
43 | def libName = "x2c-lib"
44 | // 版本号,下次更新是只需要更改版本号即可
45 | version = "1.0.6"
46 |
47 | //生成源文件
48 | task sourcesJar(type: Jar) {
49 | from android.sourceSets.main.java.srcDirs
50 | classifier = 'sources'
51 | }
52 | //生成文档
53 | task javadoc(type: Javadoc) {
54 | source = android.sourceSets.main.java.srcDirs
55 | classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
56 | options.encoding "UTF-8"
57 | options.charSet 'UTF-8'
58 | options.author true
59 | options.version true
60 | options.links "https://github.com/chengweidev"
61 | failOnError false
62 | }
63 |
64 | //文档打包成jar
65 | task javadocJar(type: Jar, dependsOn: javadoc) {
66 | classifier = 'javadoc'
67 | from javadoc.destinationDir
68 | }
69 | //拷贝javadoc文件
70 | task copyDoc(type: Copy) {
71 | from "${buildDir}/docs/"
72 | into "docs"
73 | }
74 |
75 | //上传到jcenter所需要的源码文件
76 | artifacts {
77 | archives javadocJar
78 | archives sourcesJar
79 | }
80 |
81 | // 配置maven库,生成POM.xml文件
82 | install {
83 | repositories.mavenInstaller {
84 | // This generates POM.xml with proper parameters
85 | pom {
86 | project {
87 | packaging 'aar'
88 | name 'xml 2 code libraray'
89 | url siteUrl
90 | licenses {
91 | license {
92 | name 'xml 2 code libraray'
93 | url 'https://github.com/chengweidev'
94 | }
95 | }
96 | developers {
97 | developer {
98 | id 'chengweidev'
99 | name 'chengweidev'
100 | email 'chengweidev@gmail.com'
101 | }
102 | }
103 | scm {
104 | connection gitUrl
105 | developerConnection gitUrl
106 | url siteUrl
107 | }
108 | }
109 | }
110 | }
111 | }
112 |
113 | //上传到jcenter
114 | Properties properties = new Properties()
115 | properties.load(project.rootProject.file('local.properties').newDataInputStream())
116 | bintray {
117 | user = properties.getProperty("bintray.user") //读取 local.properties 文件里面的 bintray.user
118 | key = properties.getProperty("bintray.apikey") //读取 local.properties 文件里面的 bintray.apikey
119 | configurations = ['archives']
120 | pkg {
121 | repo = "maven"
122 | name = libName //发布到JCenter上的项目名字,必须填写
123 | desc = 'xml to code' //项目描述
124 | websiteUrl = siteUrl
125 | vcsUrl = gitUrl
126 | licenses = ["Apache-2.0"]
127 | publish = true
128 | }
129 | }
--------------------------------------------------------------------------------
/x2c-lib/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/x2c-lib/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/x2c-lib/src/main/java/com/zhangyue/we/x2c/IViewCreator.java:
--------------------------------------------------------------------------------
1 | package com.zhangyue.we.x2c;
2 |
3 |
4 | import android.content.Context;
5 | import android.view.View;
6 |
7 | /**
8 | * @author:chengwei 2018/8/9
9 | * @description
10 | */
11 | public interface IViewCreator {
12 | View createView(Context context);
13 | }
14 |
--------------------------------------------------------------------------------
/x2c-lib/src/main/java/com/zhangyue/we/x2c/X2C.java:
--------------------------------------------------------------------------------
1 | package com.zhangyue.we.x2c;
2 |
3 | import android.app.Activity;
4 | import android.content.Context;
5 | import android.util.SparseArray;
6 | import android.view.LayoutInflater;
7 | import android.view.View;
8 | import android.view.ViewGroup;
9 |
10 | /**
11 | * @author:chengwei 2018/8/9
12 | * @description
13 | */
14 | public final class X2C {
15 | private static final SparseArray sSparseArray = new SparseArray<>();
16 |
17 | /**
18 | * 设置contentview,检测如果有对应的java文件,使用java文件,否则使用xml
19 | *
20 | * @param activity 上下文
21 | * @param layoutId layout的资源id
22 | */
23 | public static void setContentView(Activity activity, int layoutId) {
24 | if (activity == null) {
25 | throw new IllegalArgumentException("Activity must not be null");
26 | }
27 | View view = getView(activity, layoutId);
28 | if (view != null) {
29 | activity.setContentView(view);
30 | } else {
31 | activity.setContentView(layoutId);
32 | }
33 | }
34 |
35 | /**
36 | * 加载xml文件,检测如果有对应的java文件,使用java文件,否则使用xml
37 | *
38 | * @param context 上下文
39 | * @param layoutId layout的资源id
40 | */
41 | public static View inflate(Context context, int layoutId, ViewGroup parent) {
42 | return inflate(context, layoutId, parent, parent != null);
43 | }
44 |
45 | public static View inflate(Context context, int layoutId, ViewGroup parent, boolean attach) {
46 | return inflate(LayoutInflater.from(context), layoutId, parent, attach);
47 | }
48 |
49 | public static View inflate(LayoutInflater inflater, int layoutId, ViewGroup parent) {
50 | return inflate(inflater, layoutId, parent, parent != null);
51 | }
52 |
53 | public static View inflate(LayoutInflater inflater, int layoutId, ViewGroup parent, boolean attach) {
54 | View view = getView(inflater.getContext(), layoutId);
55 | if (view != null) {
56 | if (parent != null && attach) {
57 | Object width = view.getTag(R.id.x2c_rootview_width);
58 | Object height = view.getTag(R.id.x2c_rootview_height);
59 | if (width instanceof Integer && height instanceof Integer) {
60 | parent.addView(view, (int) width, (int) height);
61 | } else {
62 | parent.addView(view);
63 | }
64 | }
65 | return view;
66 | } else {
67 | return inflater.inflate(layoutId, parent, attach);
68 | }
69 | }
70 |
71 | public static View getView(Context context, int layoutId) {
72 | IViewCreator creator = sSparseArray.get(layoutId);
73 | if (creator == null) {
74 | try {
75 | int group = generateGroupId(layoutId);
76 | String layoutName = context.getResources().getResourceName(layoutId);
77 | layoutName = layoutName.substring(layoutName.lastIndexOf("/") + 1);
78 | String clzName = "com.zhangyue.we.x2c.X2C" + group + "_" + layoutName;
79 | creator = (IViewCreator) context.getClassLoader().loadClass(clzName).newInstance();
80 | } catch (Exception e) {
81 | e.printStackTrace();
82 | }
83 |
84 | //如果creator为空,放一个默认进去,防止每次都调用反射方法耗时
85 | if (creator == null) {
86 | creator = new DefaultCreator();
87 | }
88 | sSparseArray.put(layoutId, creator);
89 | }
90 | return creator.createView(context);
91 | }
92 |
93 | private static class DefaultCreator implements IViewCreator {
94 |
95 | @Override
96 | public View createView(Context context) {
97 | return null;
98 | }
99 | }
100 |
101 | private static int generateGroupId(int layoutId) {
102 | return layoutId >> 24;
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/x2c-lib/src/main/java/com/zhangyue/we/x2c/X2CUtils.java:
--------------------------------------------------------------------------------
1 | package com.zhangyue.we.x2c;
2 |
3 | import android.content.Context;
4 | import android.content.res.Resources;
5 | import android.content.res.TypedArray;
6 | import android.util.TypedValue;
7 |
8 | /**
9 | * @author 7hens
10 | */
11 | public final class X2CUtils {
12 |
13 | public static int getResourceIdFromAttr(Context ctx, int attr) {
14 | TypedValue outValue = new TypedValue();
15 | Resources.Theme theme = ctx.getTheme();
16 | theme.resolveAttribute(attr, outValue, true);
17 | TypedArray typedArray = theme.obtainStyledAttributes(outValue.resourceId, new int[]{attr});
18 | try {
19 | return typedArray.getResourceId(0, 0);
20 | } catch (Exception e) {
21 | typedArray.recycle();
22 | return 0;
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/x2c-lib/src/main/java/com/zhangyue/we/x2c/ano/Xml.java:
--------------------------------------------------------------------------------
1 | package com.zhangyue.we.x2c.ano;
2 |
3 | import java.lang.annotation.ElementType;
4 | import java.lang.annotation.Retention;
5 | import java.lang.annotation.RetentionPolicy;
6 | import java.lang.annotation.Target;
7 |
8 | /**
9 | * @author:chengwei 2018/8/7
10 | * @description
11 | */
12 |
13 | @Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.LOCAL_VARIABLE})
14 | @Retention(RetentionPolicy.SOURCE)
15 | public @interface Xml {
16 | String[] layouts();
17 | }
18 |
--------------------------------------------------------------------------------
/x2c-lib/src/main/res/values/ids.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/x2c-lib/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | X2C
3 |
4 |
--------------------------------------------------------------------------------